#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>

#include "..\glew\glew.h"
#include "..\glut\glut.h"

#include "..\cuCommon\cuTypes.h"

#include "glCommon.h"

#include "glCommon_string.h"

#pragma warning(disable: 4996)

namespace Gfx_n
{
  uint32 nWinW = 320;
  uint32 nWinH = 240;

  uint32 nPosX = 0;
  uint32 nPosY = 0;

  uint32 nFlags = GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH;
  uint32 nAA = 1;

  int32 nId = 0;

  bool bFullscreen = false;
};

bool ParseCommandLine(int argc, char *argv[])
{
  bool error = false;
  for (int iarg = 0; iarg < argc; iarg++)
  {
    if (strcmp(argv[iarg], GLUT_STRING_RESOLUTION) == 0)
    {
      if ( iarg+2 > argc ) 
      {
        fprintf(stderr, "Error: Invalid comand line parameters, missing resolution values\n");
        error = true;
        break;
      }
      else
      {
        Gfx_n::nWinW = atoi(argv[iarg+1]);
        Gfx_n::nWinH = atoi(argv[iarg+2]);
      }
    }
    if (strcmp(argv[iarg], GLUT_STRING_POSITION) == 0)
    {
      if ( iarg+2 > argc ) 
      {
        fprintf(stderr, "Error: Invalid comand line parameters, missing position values\n");
        error = false;
        break;
      }
      else
      {
        Gfx_n::nPosX = atoi(argv[iarg+1]);
        Gfx_n::nPosY = atoi(argv[iarg+2]);
      }
    }
    if (strcmp(argv[iarg], GLUT_STRING_FULLSCREEN) == 0)
    {
      Gfx_n::bFullscreen = true;
    }
  }
  return error;
}


// Idle() is called every time in the message processing loop. It is the main callback function 
void Idle(void);
// Display() is called whenever window content is invalidated
void Display(void);
// Keyboard() is called whenever any of the character keys are pressed
void Keyboard(uint8 key, int32 mousex, int32 mousey);
// KeyboardUp() is called whenever any of the pressed character keys is released
void KeyboardUp(uint8 key, int32 mousex, int32 mousey);
// Special() is called whenever any of the special (F1-F12, etc) keys are pressed
void Special(int32 key, int32 x, int32 y);
// SpecialUp() is called whenever any of the pressed special (F1-F12, etc) keys is released
void SpecialUp(int32 key, int32 x, int32 y);

// Reshape() is called when window size is changed
void Reshape(int32 w, int32 h);

// Functions that process mouse behaviour
// Mouse() is called whenever user clicks any button
void Mouse(int32 button, int32 state, int32 mousex, int32 mousey);
// Motion() is called whenever user holds any of the buttons while moving mouse
void Motion(int32 mousex, int32 mousey);
// PassiveMotion() is called whenever mouse moves and no buttons are pressed
void PassiveMotion(int32 mousex, int32 mousey);
// Entry() is called when mouse cursor enters / leaves current window
void Entry(int32 state);

int main(int argc, char *argv[])
{
  ParseCommandLine(argc, argv);

  glutInit( &argc, argv );  
  glutInitWindowSize(Gfx_n::nWinW, Gfx_n::nWinH);  
  glutInitWindowPosition(Gfx_n::nPosX, Gfx_n::nPosY);
  glutInitDisplayMode(Gfx_n::nFlags);

  Gfx_n::nId = glutCreateWindow("glutTemplate window");

  glutDisplayFunc(Display);
  glutIdleFunc(Idle);
  glutKeyboardFunc(Keyboard);
  glutSpecialFunc(Special);
  glutReshapeFunc(Reshape);

  if (Gfx_n::bFullscreen)
    glutFullScreen();

  glutMainLoop();

  return 0;
}

void Reshape(int32 w, int32 h)
{
  glViewport(0, 0, w, h);

  Gfx_n::nWinW = w;
  Gfx_n::nWinH = h;
}

void Display(void)
{
  glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  float4 fontColor = {1.0f, 1.0f, 0.0f, 1.0f};
  glPrintf(-1.0f, 1.0f - ((20 + 15.0f) / Gfx_n::nWinH), &fontColor, GLUT_BITMAP_9_BY_15, "FPS = %f", glFPS(true, 100));

  glutSwapBuffers();
}

void Idle(void)
{
  Display();
}

void Keyboard(uint8 key, int32 mousex, int32 mousey)
{
  switch (key)
  {
    case GLUT_KEY_ESC: 
      // any opengl resource clean-up should go here
      glutDestroyWindow(Gfx_n::nId);
      // any cpu resource clean-up should go here
      exit(0);
      break;
    default:
      break;
  }
}

void Special(int32 key, int32 mousex, int32 mousey)
{
  //switch (key)
  //{
  //  default:
  //  break;
  //}
}

void KeyboardUp(uint8 key, int32 mousex, int32 mousey)
{
  //switch (key)
  //{
  //  default:
  //  break;
  //}
}

void SpecialUp(int32 key, int32 mousex, int32 mousey)
{
  //switch (key)
  //{
  //  default:
  //  break;
  //}
}